package com.yx.fx.log.web.filter;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.StopWatch;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.yx.fx.log.web.business.LoggerBusiness;
import com.yx.fx.log.web.config.WebLogConfig;
import com.yx.fx.log.web.model.save.SaveLogger;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;
import org.springframework.web.util.ContentCachingResponseWrapper;
import org.springframework.web.util.WebUtils;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Map;

import static cn.hutool.core.util.CharsetUtil.UTF_8;
import static com.yx.fx.common.constant.BaseConstant.EIGHT;
import static com.yx.fx.common.constant.BaseConstant.ZERO;

/**
 * @author: 杨智杰
 * @date: 2021/3/18 11:49
 */
@Slf4j
@Component
public class WebLogFilter extends OncePerRequestFilter implements Ordered {

    /**
     * 把此过滤器放到最后执行
     */
    private int order = Ordered.LOWEST_PRECEDENCE - EIGHT;

    @Resource
    private LoggerBusiness loggerBusiness;

    @Resource
    private WebLogConfig webLogConfig;

    @Override
    public int getOrder() {
        return order;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        ContentCachingRequestWrapper wrapperRequest = new ContentCachingRequestWrapper(request);
        ContentCachingResponseWrapper wrapperResponse = new ContentCachingResponseWrapper(response);
        String uuid = IdUtil.fastSimpleUUID();
        StopWatch stopWatch = DateUtil.createStopWatch(uuid);
        stopWatch.start(uuid);
        filterChain.doFilter(wrapperRequest, wrapperResponse);
        stopWatch.stop();
        Long millis = stopWatch.getLastTaskTimeMillis();
        if (webLogConfig.getIsOut()) {
            if (webLogConfig.getBlackListPath().stream().noneMatch(str -> request.getRequestURI().startsWith(str))) {
                request.setCharacterEncoding(UTF_8);
                response.setCharacterEncoding(UTF_8);
                SaveLogger logger = SaveLogger.getLogger(request).setRequestBody(getRequestBody(wrapperRequest));
                String responseBody = getResponseBody(wrapperResponse);
                log.info("\n--------------------------------------------------" + uuid + "--------------------------------------------------"
                        + "\n请求信息:" + StrUtil.maxLength(JSONUtil.toJsonStr(logger), webLogConfig.getMaxLength())
                        + "\n响应信息:" + StrUtil.maxLength(responseBody, webLogConfig.getMaxLength())
                        + "\n请求耗时(毫秒):" + millis
                        + "\n日志入库:" + webLogConfig.getDbSave()
                        + "\n---------------------------------------------------" + uuid + "---------------------------------------------------\n");
                logger.setHeaders(getHeaders(wrapperRequest)).setResponseBody(responseBody)
                        .setAnswer(millis).setCreateTime(DateUtil.now());
                if (webLogConfig.getDbSave()) {
                    loggerBusiness.setCaChe(logger);
                }
            }

        }
        wrapperResponse.copyBodyToResponse();
    }

    private String getRequestBody(ContentCachingRequestWrapper request) {
        ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
        if (wrapper != null) {
            byte[] buf = wrapper.getContentAsByteArray();
            if (buf.length > ZERO) {
                String payload;
                try {
                    payload = new String(buf, ZERO, buf.length, wrapper.getCharacterEncoding());
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                    payload = e.toString();
                }
                return payload;
            }
        }
        return null;
    }

    private String getResponseBody(ContentCachingResponseWrapper response) {
        ContentCachingResponseWrapper wrapper = WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class);
        if (wrapper != null) {
            byte[] buf = wrapper.getContentAsByteArray();
            if (buf.length > ZERO) {
                String payload;
                try {
                    payload = new String(buf, ZERO, buf.length, wrapper.getCharacterEncoding());
                } catch (UnsupportedEncodingException e) {
                    e.printStackTrace();
                    payload = e.toString();
                }
                return payload;
            }
        }
        return null;
    }

    private String getHeaders(ContentCachingRequestWrapper request) {
        Map<String, String> map = new LinkedHashMap<>();
        Enumeration headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String key = (String) headerNames.nextElement();
            String value = request.getHeader(key);
            map.put(key, value);
        }
        return CollUtil.isNotEmpty(map)
                ? JSONUtil.toJsonStr(map)
                : null;
    }
}
